##########################
#                        #
#  PL0-Idiom Interpreter #
#                        #
##########################

### import modules needed for Interpreter

import pl0_parser
import pl0_generator


### define interpreter methods

### allocate symbolic memory adresses
def CalcSymMA(op, stack):
            if (len(stack) == 1): rs1 = '0'
            else: rs1 = stack.pop()
            rs2 = stack.pop()
            if (rs1.isalpha()):
                if (rs2.isalpha()):
                    op = op
                elif (rs2.isdigit()):
                    op = op + 'N'
            elif (rs1.isdigit()):
                t = rs1
                rs1 = rs2
                rs2 = t

            return op, rs1, rs2

### Convert infix clause to preafix
def InftoPos(infix):
    postfix = []
    stack = []

    prio = {'+': 0, '-': 0, '*': 1, '/': 1, '(': None, ')': None}

    if (infix[0] == '+'): infix = infix[1:]
    elif (infix[0] == '-'): infix.insert(0, '0')

    for i in infix:
        if (i.isalnum()): postfix.append(i)
        elif (i == '('): stack.append(i)
        elif (prio.has_key(i) and len(stack) == 0): stack.append(i)
        elif (prio.has_key(i) and len(stack) > 0):
            while (len(stack) > 0 and prio[i] <= prio[stack[len(stack) - 1]]):
                postfix.append(stack.pop())
            stack.append(i)
        elif (i == ')'):
            while (len(stack) > 0 and stack[len(stack) - 1] != '('):
                postfix.append(stack.pop())
            stack.pop()
        while (infix[infix.index(i)] == infix[len(infix) - 1] and len(stack) > 0):
            postfix.append(stack.pop())

    [postfix.remove(i) for i in postfix[:] if i == '(' or i == ')']

    return postfix

### Evaluate postfix clause to assembler code
def EvalPos(postfix, target, code, pos):
    stack = []
    postfix.reverse()
    #assem = []

    for i in postfix:
        code = []
        op = ''
        rt = target[1]
        if (len(postfix) > 1):
            if (i.isalnum()): stack.append(i)
            elif (i == '*'):
                op, rs1, rs2 = CalcSymMA('MUL', stack)
            elif (i == '/'):
                op, rs1, rs2 = CalcSymMA('DIV', stack)
            elif (i == '+'):
                op, rs1, rs2 = CalcSymMA('ADD', stack)
            elif (i == '-'):
                op, rs1, rs2 = CalcSymMA('SUB', stack)
            rt = target[1]
            if (i == postfix[len(postfix) - 1] and len(stack) == 0): stack.append(rt)
        else:
            op, rs1, rs2 = CalcSymMA('ADD', stack)
        code.insert(pos, pl0_generator.Instruction('', op, [rs1, rs2, rt]))


### Interpreter

code = pl0_parser.program()
for i in code[:]:
    ins = i.ins
    if (ins[1] == 'postfix'):
        infix = ins[0]
        if (infix[1] == '='):
            ins[0] = InftoPos(infix[2:])
            ins[2] = infix[:2]
            EvalPos(ins[0], ins[2], code, code.index(i))
    print ins

for i in code:
    print i.ins
